package ahg;

import static robocode.util.Utils.normalRelativeAngleDegrees;

import robocode.BulletHitEvent;
import robocode.BulletMissedEvent;
import robocode.HitByBulletEvent;
import robocode.HitWallEvent;
import robocode.Robot;
import robocode.ScannedRobotEvent;

/**
 * <code>CakeBot</code> is my implementation of the <code>Walls</code> robot.
 * @author - Tony Gaskell
 */

public class CakeBot extends Robot {

  boolean setup;
  boolean attack;  // When the robot attacks

  int miss;  // Counts how many of the bots shots miss.
  double moveAmount; // How much to move
  
  /**
   * run: Bot searches for target.
   */
  public void run() {
    setup = true;
    // Initialize setup variables.
    while (setup) {
      // Initialize moveAmount to the maximum possible for this battlefield.
      moveAmount = Math.max(getBattleFieldWidth(), getBattleFieldHeight());
      setAdjustGunForRobotTurn(true);
      setAdjustRadarForGunTurn(false);

      attack = true;
      miss = 0;
      setup = false;
    }
    while (true) {
      ahead(moveAmount / 2);
      turnGunLeft(360);
      attack = true;
    }
  }
  /**
   * Shoots and approaches target.
   * @param scanned ScannedRobotEvent
   */
  public void onScannedRobot(ScannedRobotEvent scanned) {
    if (attack) {
    turnGunRight(lockOnBot(scanned,scanned.getBearing(), getHeading(), getRadarHeading()));
    fire(smartShot(scanned));
    ahead(scanned.getDistance() / 5);
    }
  }

  /**
   * Keeps track of how many of your shots miss.
   * If too many shots miss, stops attacking.
   * @param miss BulletMissedEvent
   */
  public void onBulletMissed(BulletMissedEvent miss) {
    if (this.miss > 5) {
      attack = false;
    }
    this.miss++;
  }
  
  /**
   *  If you are hit by a bullet, resets your miss counter.
   *  You want to return fire if you're being attacked.
   *  @param hit BulletHitEvent
   */
  public void onBulletHit(BulletHitEvent hit) {
    miss = 0;
    attack = true;
  }
  
  /**
   * Fires a bullet and attempts to veer away from enemy location.
   * Veers left or right of target based on which side they attacked from.
   * @param hit HitbyBulletEvent
   */
  public void onHitByBullet(HitByBulletEvent hit) {
    fire(3);
    attack = false;
    turnRight(evade(hit.getBearing()));
    ahead(moveAmount / 2 );
    attack = true;
  }
  
  /**
   * Turns around when runs into a wall or another bot.
   * @param hit hitWallEvent
   */
  public void onHitWall(HitWallEvent hit) {
    turnLeft(180);
  }

  /**
   * Changes weapon speed based on distance to target.
   * Stronger shots for closer targets.
   * Weaker shots for further targets.
   * @param scanned ScannedRobotEvent
   * @return Power of the shot to be fired.
   */
  public double smartShot(ScannedRobotEvent scanned) {
    if (scanned.getDistance() >= (moveAmount / 3)) {
      return 1;
    }
    if (scanned.getDistance() >= (2 * moveAmount / 3)) {
      return 2;
    }
    else {
      return 3;
    }
  }
  
  /**
   * Tracks scanned target with gun.
   * @param scanned ScannedRobotEvent
   * @param bearing of the scanned target
   * @param heading of your bot
   * @param radarHeading of your bot
   * @return Degrees to turn right.
   */
  public double lockOnBot(ScannedRobotEvent scanned, double bearing,
      double heading, double radarHeading) {
    return normalRelativeAngleDegrees(bearing + (heading - radarHeading));
  }
  
  /**
   * Changes direction upon being hit by a bullet.
   * Turns 45 degrees into the heading where the bullet hit.
   * @param bearing which the bullet came from.
   * @return degrees to adjust your current heading by
   */
  public double evade(double bearing) {
    if (bearing > 0) {
      return (normalRelativeAngleDegrees(bearing) + 45);
    } 
    else {
      return (normalRelativeAngleDegrees(bearing) - 45);
    }
  }
}

